﻿// Copyright (c) 2014 Converter Systems LLC

using Opc.Ua;
using Opc.Ua.Bindings;
using System;
using System.Configuration;
using System.Diagnostics;
using System.Net;

namespace ConverterSystems.ServiceModel
{
    /// <summary>
    /// Builds ITransportChannels.
    /// </summary>
    internal sealed class TransportChannelBuilder
    {
        private ApplicationConfiguration _appConfiguration;

        public TransportChannelBuilder(ApplicationConfiguration appConfiguration)
        {
            if (appConfiguration == null) throw new ArgumentNullException("appConfiguration");
            _appConfiguration = appConfiguration;
        }

        /// <summary>
        /// Builds an ITransportChannel based on the endpoint scheme.
        /// </summary>
        public ITransportChannel Build(string uriOrName, ref TransportChannelSettings settings)
        {
            if (uriOrName == null) throw new ArgumentNullException("uriOrName");
            var uri = GetUriFromConnectionStrings(uriOrName);
            ITransportChannel channel;
            switch (uri.Scheme)
            {
                case "opc.tcp":
                    channel = new TcpTransportChannel();
                    break;

                case "https":
                    channel = new HttpsTransportChannel();
                    break;

                default:
                    throw new ArgumentOutOfRangeException("endpointUrl", "Only 'opc.tcp' and 'https' transports please.");
            }
            var description = new EndpointDescription
            {
                EndpointUrl = uri.ToString(),
                SecurityMode = MessageSecurityMode.None,
                SecurityPolicyUri = "http://opcfoundation.org/UA/SecurityPolicy#None"
            };
            var configuration = EndpointConfiguration.Create(_appConfiguration);
            settings = new TransportChannelSettings
            {
                Description = description,
                Configuration = configuration,
                ClientCertificate = _appConfiguration.SecurityConfiguration.ApplicationCertificate.Find(true),
                CertificateValidator = _appConfiguration.CertificateValidator.GetChannelValidator(),
                NamespaceUris = new NamespaceTable(),
                Factory = EncodeableFactory.GlobalFactory
            };
            channel.Initialize(uri, settings);
            return channel;
        }

        /// <summary>
        /// Builds an ITransportChannel based on the endpoint scheme.
        /// </summary>
        public ITransportChannel Build(string uriOrName)
        {
            TransportChannelSettings settings = null;
            return this.Build(uriOrName, ref settings);
        }

        private static Uri GetUriFromConnectionStrings(string endpointUrlOrName)
        {
            var ep = ConfigurationManager.ConnectionStrings[endpointUrlOrName];
            if (ep != null)
            {
                endpointUrlOrName = ep.ConnectionString;
            }
            var uri = new UriBuilder(endpointUrlOrName);
            if (string.Equals(uri.Host, "localhost", StringComparison.OrdinalIgnoreCase))
            {
                uri.Host = Dns.GetHostName();
            }
            return uri.Uri;
        }
    }
}